#include "spi.h"

u8 SpiTimeOut=0;  //Spi通信超时故障计数
//以下是SPI模块的初始化代码，配置成主机模式，访问SD Card/W25Q64/NRF24L01
//SPI口初始化
//这里针是对SPI2的初始化

static SpiPort_T Spi2Ports = {
    .MOSI = {GPIOB, 15, GPIO_Pin_15},
    .MISO = {GPIOB, 14, GPIO_Pin_14},
    .SCK = {GPIOB, 13, GPIO_Pin_13},
    .NSS = {GPIOB, 12, GPIO_Pin_12},
};

//static SpiPort_T Spi3Ports = {
//    .MOSI = {GPIOB, 5, GPIO_Pin_5},
//    .MISO = {GPIOB, 4, GPIO_Pin_4},
//    .SCK = {GPIOB, 3, GPIO_Pin_3},
//    .NSS = {GPIOD, 7, GPIO_Pin_7},
//};

static ImuSensorx Spi3_Sensor_Adis16505 =
    {
        .Spi_Imu.MOSI = {GPIOB, 5, GPIO_Pin_5},
        .Spi_Imu.MISO = {GPIOB, 4, GPIO_Pin_4},
        .Spi_Imu.SCK = {GPIOB, 3, GPIO_Pin_3},
        .Spi_Imu.NSS = {GPIOD, 7, GPIO_Pin_7},
        .DR = {GPIOB, 6, GPIO_Pin_6},
        .SYNC = {GPIOD, 5, GPIO_Pin_5},
        .RST = {GPIOD, 6, GPIO_Pin_6},
};

void Board_SPI2_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //PORTB时钟使能
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);  //SPI2时钟使能

    GPIO_InitStructure.GPIO_Pin = Spi2Ports.MOSI.pin | Spi2Ports.MISO.pin | Spi2Ports.SCK.pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB

    GPIO_InitStructure.GPIO_Pin = Spi2Ports.NSS.pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //PB6/7推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB, GPIO_Pin_12); //初始化时片选信号为高

    /* SPI2 configuration */
    SPI_Cmd(SPI2, DISABLE);                                            //必须先禁能,才能改变MODE
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                      //设置SPI工作模式:设置为主SPI
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                  //设置SPI的数据大小:SPI发送接收8位帧结构
                                                                       //  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;    //串行同步时钟的空闲状态为高电平
                                                                       //  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;  //串行同步时钟的第二个跳变沿（上升或下降）数据被采样
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                         //串行同步时钟的空闲状态为高电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                           //NSS信号由硬件（NSS管脚）还是软件（使用SSI位）管理:内部NSS信号有SSI位控制
                                                                        //   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;    //定义波特率预分频的值:波特率预分频值为256
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; //定义波特率预分频的值:波特率预分频值为256
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                  //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    SPI_InitStructure.SPI_CRCPolynomial = 7;                            //CRC值计算的多项式
    SPI_Init(SPI2, &SPI_InitStructure);                                 //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
    SPI_Cmd(SPI2, ENABLE);                                              //使能SPI外设
    //  SPI2_ReadWriteByte(0xff);//启动传输
}

void Board_SPI3_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); //PORTB时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);                        //PORTD时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);                         //
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);                         //SPI3时钟使能

    GPIO_InitStructure.GPIO_Pin = Spi3_Sensor_Adis16505.Spi_Imu.MOSI.pin | Spi3_Sensor_Adis16505.Spi_Imu.MISO.pin | Spi3_Sensor_Adis16505.Spi_Imu.SCK.pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB

    GPIO_InitStructure.GPIO_Pin = Spi3_Sensor_Adis16505.Spi_Imu.NSS.pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //PD7推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
    GPIO_SetBits(Spi3_Sensor_Adis16505.Spi_Imu.NSS.port, Spi3_Sensor_Adis16505.Spi_Imu.NSS.pin); //初始化时片选信号为高

    //  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
    //  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    //  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    //  GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    /* *********************************************SPI3 configuration ***************************************************/
    SPI_Cmd(SPI3, DISABLE);                                             //必须先禁能,才能改变MODE
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                       //设置SPI工作模式:设置为主SPI
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;                  //设置SPI的数据大小:SPI发送接收8位帧结构
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                         //串行同步时钟的空闲状态为高电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                        //串行同步时钟的第二个跳变沿（上升或下降）数据被采样
                                                                        //  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;    //串行同步时钟的空闲状态为高电平
                                                                        //  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                           //NSS信号由硬件（NSS管脚）还是软件（使用SSI位）管理:内部NSS信号有SSI位控制
                                                                        //SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;    //定义波特率预分频的值:波特率预分频值为256
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;//SPI_BaudRatePrescaler_32; //定义波特率预分频的值:波特率预分频值为32,APB1时钟为36MHZ，ADIS16505要求时钟不超过2Mhz，所以频率为36m/32=1.125M
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                  //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    SPI_InitStructure.SPI_CRCPolynomial = 7;                            //CRC值计算的多项式
    SPI_Init(SPI3, &SPI_InitStructure);                                 //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
    SPI_Cmd(SPI3, ENABLE);                                              //使能SPI外设
    //  SPI2_ReadWriteByte(0xff);//启动传输
}

//SPI 速度设置函数
//SpeedSet:
//SPI_BaudRatePrescaler_2   2分频
//SPI_BaudRatePrescaler_8   8分频
//SPI_BaudRatePrescaler_16  16分频
//SPI_BaudRatePrescaler_256 256分频

void Board_SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
    SPI2->CR1 &= 0XFFC7;
    SPI2->CR1 |= SPI_BaudRatePrescaler; //设置SPI2速度
    SPI_Cmd(SPI2, ENABLE);
}

//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 Board_SPI2_ReadWriteByte(u8 TxData)
{
    u16 retry = 0;
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
    {
        retry++;
        if (retry > 20000)
            return 0;
    }
    SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
    //       SPI_I2S_SendData(SPI2, 0X8F); //通过外设SPIx发送一个数据
    retry = 0;

    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
    {
        retry++;
        if (retry > 20000)
            return 0;
    }
    return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}

//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u16 Board_SPI3_ReadWriteByte(u16 TxData)
{
    u16 retry = 0;
    while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
    {
        retry++;
        if (retry > 20000)
        {
           SpiTimeOut++;   //Spi通信超时故障
        }
            return 0;
    }
    SPI_I2S_SendData(SPI3, TxData); //通过外设SPIx发送一个数据

    retry = 0;
    while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
    {
        retry++;
        if (retry > 20000)
        {
          SpiTimeOut++;   //Spi通信超时故障
          return 0;
        }
    }
    
    SpiTimeOut=0;   //如果Imu通信正常，则清零
    
    return SPI_I2S_ReceiveData(SPI3); //返回通过SPIx最近接收的数据
}












